package com.zmp.kotlinnote.exchange

import com.zmp.kotlinnote.entry.methodDel
import org.junit.Test

/**
 *@author zmp
 *Created by zmp on 2018/12/20
 */

/**
 * TODO 双冒号函数--将函数当做变量进行赋值或者传递
 *
 *
 *
 * TODO 扩展函数与普通函数当做参数时互相转换
 *
 *
 * TODO 转换过程不支持匿名，复杂参数注意泛型约束
 */
class DoubleColon {
    @Test
    fun colon() {
        //左右一  赋值
//        val add = ::methodAdd
        val add = fun Int.(b:Int): Int { //不支持匿名
            return this + b
        }
//        add.invoke(2,3)

        methodAdd(1, 3).log()


        //左右一  传参
        method(2, 3, add).log()
//        method(2, 3, fun Int.(b:Int): Int { //不支持匿名
//////            return this + b
//////        }).log()

        method(2, 3, fun(a, b): Int {
            return a + b
        }).log()

        method(2, 4, ::methodAdd).log()
        method(2, 4, ::methodAdd).log()
        method2(2, 4, ::methodAdd).log()

//        method2(2, 4, fun(a, b): Int {//不支持匿名
//            return a + b
//        }).log()

        method2(2, 4, fun Int.(b:Int): Int {
            return this + b
        }).log()


        method2(2, 4, Int::methodDel).log()
        method2(2, 4, fun Int.(b: Int): Int {
            return this + b
        }).log()
        "".let(String::cc)


        method3(1, "ss", Int::ss)
        method4(1, "ss", Int::ss)
        method5(1, Int::run)


        val ww: (Int, Int.() -> Int) -> Int = ::with3
        val rr: Int.(Int.() -> Int) -> Int = Int::run3
//        method5(1, ::with)
        method5(1, ::with2)
        method5(1, Int::run)
        method5(1, Int::run2)
        method5(1, Int::run3)
        method5(1, ww)
//        method5(1, ::with3) //报错

        method6(1, ::with)
//        method6(1, Int::run3) //报错
        method6(1, rr)
//        method6(1, Int::run) //报错

    }

    private infix fun add(i: Int) = i


    val ddd = fun(a: Int, b: Int): Int {
        return a + b
    }


    fun methodAdd(i: Int, j: Int) = j + i


    private fun method(i: Int, j: Int, b: (Int, Int) -> Int) = b(i, j)

    private fun method2(i: Int, j: Int, b: Int.(Int) -> Int) = i.b(j)

    private fun method3(i: Int, j: String, b: Int.(String) -> String) = i.b(j)


    private fun method4(i: Int, j: String, b: (Int, String) -> String) = b(i, j)


    /**
     * with run 的相互转换
     */
    private fun method5(i: Int, b: Int.(Int.() -> Int) -> Int) = i.b {
        this + 1
    }

    private fun method6(i: Int, b: (Int, Int.() -> Int) -> Int) = b.invoke(i) {
        this + 1
    }
}

fun String.cc() {

}

fun Int.ss(a: String): String {
    return "$this$a"
}

public fun with2(receiver: Int, block: Int.() -> Int): Int {

    return receiver.block()
}

public inline fun Int.run2(block: Int.() -> Int): Int {
    return block()
}

public fun <T> with3(receiver: T, block: T.() -> T): T {

    return receiver.block()
}

public inline fun <T,R> T.run3(block: T.() -> R): R {
    return block()
}






